using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Builder.Extensions;
using Microsoft.AspNetCore;

namespace HelloWorldWithMiddleware
{
    public class MiddlewareHtml
    {
        readonly RequestDelegate _next;

        public MiddlewareHtml(RequestDelegate next) => _next = next;

        public async Task Invoke(HttpContext context)
        {
            context.Items["Content"] += "<html><body>\n";
            await _next.Invoke(context);
            context.Items["Content"] += "</body></html>";

            context.Response.Headers.Add("content-type", "text/html");
            await context.Response.WriteAsync(context.Items["Content"] as string);
        }
    }

    public class MiddlewareTitle
    {
        readonly RequestDelegate _next;

        public MiddlewareTitle(RequestDelegate next) => _next = next;

        public async Task Invoke(HttpContext context)
        {
            context.Items["Content"] += "<h1>Contrasting MapWhen with UseWhen</h1>\n";
            await _next.Invoke(context);
        }
    }

    public class MiddlewareFooter
    {
        readonly RequestDelegate _next;

        public MiddlewareFooter(RequestDelegate next) => _next = next;

        public async Task Invoke(HttpContext context)
        {
            await _next.Invoke(context);
            context.Items["Content"] += "<footer><hr/><strong>Middleware Footer</strong></footer>\n";
        }
    }


    public class MiddlewareUsedByMapWhen
    {
        readonly RequestDelegate _next;

        public MiddlewareUsedByMapWhen(RequestDelegate next) => _next = next;

        public async Task Invoke(HttpContext context)
        {
            context.Items["Content"] += @"<strong>This message generated by MiddlewareUsedByMapWhen</strong>\n
            <p>
                MapWhen branches the middleware execution hence you will not see the footer here.
            </p>
            ";

            await _next.Invoke(context);
        }
    }

    public class MiddlewareUsedByUseWhen
    {
        readonly RequestDelegate _next;

        public MiddlewareUsedByUseWhen(RequestDelegate next) => _next = next;

        public async Task Invoke(HttpContext context)
        {
            context.Items["Content"] += @"<strong>This message generated by MiddlewareUsedByUseWhen</strong>\n
            <p>
                UseWhen makes the execution of a Middleware conditional based on certain condition. In contrast with MapWhen, it does not branch the execution. Hence you will
                see the footer here.
            </p>
            ";

            await _next.Invoke(context);
        }
    }

    public class MiddlewareNavigation
    {
        readonly RequestDelegate _next;

        public MiddlewareNavigation(RequestDelegate next) => _next = next;

        public async Task Invoke(HttpContext context)
        {
            context.Items["Content"] += @"<ul>
                   <li><a href=""/map-when-example"">/map-when-example</a>.</li>
                   <li><a href=""/use-when-example"">/use-when-example</a>.</li>
                </ul>";

            await _next.Invoke(context);
        }
    }
    public class Startup
    {
        public void Configure(IApplicationBuilder app)
        {
            app.UseMiddleware<MiddlewareHtml>();
            app.UseMiddleware<MiddlewareTitle>();

            app.MapWhen(context => context.Request.Path.StartsWithSegments("/map-when-example"), appBuilder => appBuilder.UseMiddleware<MiddlewareUsedByMapWhen>());
            app.UseWhen(context => context.Request.Path.StartsWithSegments("/use-when-example"), appBuilder => appBuilder.UseMiddleware<MiddlewareUsedByUseWhen>());

            app.UseMiddleware<MiddlewareNavigation>();
            app.UseMiddleware<MiddlewareFooter>();
        }
    }

    public class Program
    {
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .UseEnvironment("Development");
    }
}